#include "device.h"
#include "component.h"

/* 默认LED组件的昵称 */
#ifndef KOS_PARAM_LED_ALIAS
#define KOS_PARAM_LED_ALIAS  LED_ALIAS_FRONT
#endif

/* LED虚拟硬件接口定义 */
#define   VHW_PIN_LED0            vPIN_L0
#define   VHW_PIN_LED1            vPIN_L1
#define   VHW_PIN_LED2            vPIN_L2
#define   VHW_PIN_LED3            vPIN_L3
#define   VHW_PIN_LED4            vPIN_L4
#define   VHW_PIN_LED5            vPIN_L5
#define   VHW_PIN_LED6            vPIN_L6
#define   VHW_PIN_LED7            vPIN_L7
#define   VHW_PIN_LED8            vPIN_L8
#define   VHW_PIN_LED9            vPIN_L9
#define   VHW_PIN_LED_BACKSPACE   vPIN_L10 //*键
#define   VHW_PIN_LED_ENTER       vPIN_L11 //#键
#define   VHW_PIN_LED_OPEN        vPIN_L12 
#define   VHW_PIN_LED_CLOSE       vPIN_L13
#define   VHW_PIN_LED_RED         vPIN_L14
#define   VHW_PIN_LED_GREEN       vPIN_L15
#define   VHW_PIN_LED_BAT         vPIN_L16 //电量灯灯-白灯
#define   VHW_PIN_LED_FS          vPIN_L17 //反锁灯
#define   VHW_PIN_LED_KEY         vPIN_L18 //键盘灯整体控制
#define   VHW_PIN_LED_LP          vPIN_L19 //低电量灯-红灯
#define   VHW_PIN_LED_PWM_R       vPIN_L20 //红灯-笑脸
#define   VHW_PIN_LED_PWM_G       vPIN_L21 //绿灯-笑脸
#define   VHW_PIN_LED_PWM_B       vPIN_L22 //蓝灯-笑脸
#define   VHW_PIN_LED_LOCKED      vPIN_L23 //上锁按键灯
#define   VHW_PIN_LED_BACK_R      vPIN_L24
#define   VHW_PIN_LED_BACK_G      vPIN_L25
#define   VHW_PIN_LED_DOORBELL    vPIN_L26 //门铃灯
#define   VHW_PIN_LED_BLE_CFG     vPIN_L27 //蓝牙配网灯 
#define   VHW_PIN_LED_SHOW_LED     vPIN_L28 //屏幕灯按键灯
#define   VHW_PIN_LED_CARD        vPIN_L29 //刷卡指示灯

#define VHW_PIN_LED_LOGO_W vPIN_L31 ///< 白灯-logo
#define VHW_PIN_LED_LOGO_R vPIN_L32 ///< 红灯-logo
#define VHW_PIN_LED_LOGO_G vPIN_L33 ///< 绿灯-logo
#define VHW_PIN_LED_LOGO_B vPIN_L34 ///< 蓝灯-logo

#define VHW_LED_PWM vPWM_3

/* 调试打印接口 */
#define LED_LOG(format, ...)   __OSAL_LOG("[led.c] " C_GREEN format C_NONE, ##__VA_ARGS__)

/* LED闪烁事件 */
#define EVENT_LED_FLASH  ( 0X00000001 )

/* LED闪烁事件处理周期 */
#define LED_FLASH_EVT_PROC_CYCLE  (10)

/* 闪烁LED数据表 */
#define LED_FLASHING_MAX_QTY    5

static struct
{
    char name[15];  				//LED名称
    uint8_t count;  				//计数
    uint8_t times;  				//闪烁总次数：0XFF表示永久闪烁
    uint32_t cycle; 				//闪烁周期
    uint32_t timestamp;				//计时
}ledFlashList[LED_FLASHING_MAX_QTY];

static uint8_t ledAnimation = 0;
static uint8_t pwm_dir = 0;
static float   pwm_duty_cycle = 0;

#if KOS_PARAM_LED_ROUND_KEYBOARD
static uint8_t led_enter_status = 1; //#键LED的状态（确认键LED的状态）
#endif

static ErrorStatus Led_IsFlash(const char *name);

/**
  * @brief  笑脸灯PWM控制（呼吸效果）
  *         
  * @note   该函数在硬件TIMER中断里面运行（周期1ms）
  */
static void Led_PwmSet(VirtualHardware_enum_t dev, void *data, uint32_t len)
{
    if (pwm_duty_cycle > 0)
    {
        if (pwm_dir == 0)
        {
            /* 呼吸渐亮 */
            pwm_duty_cycle += 0.1f;
            if(pwm_duty_cycle >= 100)
            {
                pwm_dir = 1;
            }
        }
        else
        {
            /* 呼吸渐灭 */
            pwm_duty_cycle -= 0.1f;
        }
        Device_SetPwm(VHW_LED_PWM, 2000, pwm_duty_cycle);
    }
}

/**
  * @brief  控制LED
  *         
  * @param  dev：LED设备
  * @param  ctrl：PIN设备控制参数, 0:打开  1:关闭  2:取反 
  * @return 成功/失败
  */
static ErrorStatus Led_Control(VirtualHardware_enum_t dev, uint8_t ctrl)
{
    if ((ctrl == 0) && (dev == VHW_PIN_LED_PWM_R || dev == VHW_PIN_LED_PWM_G || dev == VHW_PIN_LED_PWM_B))
    {
        if (dev == VHW_PIN_LED_PWM_R)
        {
            Device_Write(VHW_PIN_LED_PWM_R, NULL, 0, 0);
            Device_Write(VHW_PIN_LED_PWM_G, NULL, 0, 1);
            Device_Write(VHW_PIN_LED_PWM_B, NULL, 0, 1);
        }
        else if (dev == VHW_PIN_LED_PWM_G)
        {
            Device_Write(VHW_PIN_LED_PWM_R, NULL, 0, 1);
            Device_Write(VHW_PIN_LED_PWM_G, NULL, 0, 0);
            Device_Write(VHW_PIN_LED_PWM_B, NULL, 0, 1);
        }
        else
        {
            Device_Write(VHW_PIN_LED_PWM_R, NULL, 0, 1);
            Device_Write(VHW_PIN_LED_PWM_G, NULL, 0, 1);
            Device_Write(VHW_PIN_LED_PWM_B, NULL, 0, 0);
        }
        Device_EnterCritical();
        pwm_duty_cycle = 0.1;
        pwm_dir = 0;
        Device_ExitCritical();
        return SUCCESS;
    }

#if KOS_PARAM_LED_ROUND_KEYBOARD //圆形键盘（红绿灯和#键灯在同一个位置，要做特殊处理）
    //< 如果当前需要点亮#键的灯，且红绿灯正在闪烁：就禁止#键灯点亮，等闪烁结束后才能亮
    if (dev == VHW_PIN_LED_ENTER)
    {
        led_enter_status = ctrl;
        if ((ctrl == 0) && (Led_IsFlash("LED_RED") == SUCCESS || Led_IsFlash("LED_GREEN") == SUCCESS))
        {
            return ERROR;
        }
    }
    else if ((ctrl == 0) && (dev == VHW_PIN_LED_RED || dev == VHW_PIN_LED_GREEN))
    {
        Device_Write(VHW_PIN_LED_ENTER, NULL, 0, 1);
    }
#endif

    if (ctrl == 0 || ctrl == 1 || ctrl == 2)
    {
        Device_Write(dev, NULL, 0, ctrl);
        return SUCCESS;
    }
    return ERROR;
}

static void Led_SetEnterLed(void)
{
#if KOS_PARAM_LED_ROUND_KEYBOARD //圆形键盘（红绿灯和#键灯在同一个位置，要做特殊处理）
    if (Led_IsFlash("LED_RED") == ERROR && Led_IsFlash("LED_GREEN") == ERROR)
    {
        Device_Write(VHW_PIN_LED_ENTER, NULL, 0, led_enter_status);
    }
#endif
}

/**
  * @brief  LED控制指令
  * @param cmd:控制命令
  * @param  ctrl：PIN设备控制参数, 0:打开  1:关闭  2:取反 
  * @return 成功/失败
  */
static ErrorStatus Led_Write(const char *cmd, uint8_t ctrl)
{
	VirtualHardware_enum_t dev;

	if (strncmp(cmd, "LED_", 4) == 0)
    {
		if (strcmp(cmd, "LED_OPEN") == 0)
		{
			dev = VHW_PIN_LED_OPEN;
		}
		else if (strcmp(cmd, "LED_CLOSE") == 0)
		{
			dev = VHW_PIN_LED_CLOSE;
		}
		else if (strcmp(cmd, "LED_RED") == 0)
		{
			dev = VHW_PIN_LED_RED;
		}
		else if (strcmp(cmd, "LED_GREEN") == 0)
		{
			dev = VHW_PIN_LED_GREEN;
		}
		else if (strcmp(cmd, "LED_BAT") == 0)
		{
			dev = VHW_PIN_LED_BAT;
		}
        else if (strcmp(cmd, "LED_LP") == 0)
		{
			dev = VHW_PIN_LED_LP;
		}
		else if (strcmp(cmd, "LED_FS") == 0)
		{
			dev = VHW_PIN_LED_FS;
		}
        else if (strcmp(cmd, "LED_LOCK") == 0)
        {
            dev = VHW_PIN_LED_LOCKED;
        }
        else if (strcmp(cmd, "LED_PWM_R") == 0)
        {
            dev = VHW_PIN_LED_PWM_R;
        }
        else if (strcmp(cmd, "LED_PWM_G") == 0)
        {
            dev = VHW_PIN_LED_PWM_G;
        }
        else if (strcmp(cmd, "LED_PWM_B") == 0)
        {
            dev = VHW_PIN_LED_PWM_B;
        }
        else if (strcmp(cmd, "LED_BACK_R") == 0)
        {
            dev = VHW_PIN_LED_BACK_R;
        }
        else if (strcmp(cmd, "LED_BACK_G") == 0)
        {
            dev = VHW_PIN_LED_BACK_G;
        }
        else if (strcmp(cmd, "LED_BLE_CFG") == 0)
        {
            dev = VHW_PIN_LED_BLE_CFG;
        }
        else if (strcmp(cmd, "LED_SHOW_LED") == 0)
        {
            dev = VHW_PIN_LED_SHOW_LED;
        }
        else if (strcmp(cmd, "LED_CARD") == 0)
        {
            dev = VHW_PIN_LED_CARD;
        }
        else if (strcmp(cmd, "LED_LOGO_W") == 0)
        {
            dev = VHW_PIN_LED_LOGO_W;
        }
        else if (strcmp(cmd, "LED_LOGO_R") == 0)
        {
            dev = VHW_PIN_LED_LOGO_R;
        }
        else if (strcmp(cmd, "LED_LOGO_G") == 0)
        {
            dev = VHW_PIN_LED_LOGO_G;
        }
        else if (strcmp(cmd, "LED_LOGO_B") == 0)
        {
            dev = VHW_PIN_LED_LOGO_B;
        }
        else
        {
            return ERROR;
        }
        return Led_Control(dev, ctrl);
    }
    else if (strncmp(cmd, "LED", 3) == 0)//背光灯处理
	{
		const char ledAllTag[] = "0123456789*#KDL";
		const char *pTmp = NULL;
		uint8_t len = strlen(cmd) - 3;

		if (len == 0)
		{
			len = sizeof(ledAllTag) - 1;
			pTmp = ledAllTag;
		}
        else
        {
            pTmp = &cmd[3];
        }

        for (uint8_t i = 0; i < len; i++)
        {
            if (pTmp[i] == '*')
            {
                dev = VHW_PIN_LED_BACKSPACE;
            }
            else if (pTmp[i] == '#')
            {
                dev = VHW_PIN_LED_ENTER;
            }
            else if (pTmp[i] == 'K')
            {
                dev = VHW_PIN_LED_KEY;
            }
            else if (pTmp[i] == 'D')
            {
                dev = VHW_PIN_LED_DOORBELL;
            }
            else if (pTmp[i] == 'L')
            {
                dev = VHW_PIN_LED_LOCKED;
            }
            else
            {
                dev = (VirtualHardware_enum_t)(VHW_PIN_LED0 + (pTmp[i] - '0'));
            }
            Led_Control(dev, ctrl);
        }
        return SUCCESS;
    }
	return ERROR;
}

/**
  * @brief  比较两个LED的名称是否相同
  *         
  * @param  pStr1：LED名称   
  * @param  pStr2：LED名称  
  * @return 成功/失败
  */
static ErrorStatus Led_Strcmp(const char *pStr1, const char *pStr2)
{
	if ((strncmp(pStr1, "LED_", 4) == 0) || (strncmp(pStr2, "LED_", 4) == 0))
	{
		if (strcmp(pStr1, pStr2) == 0)
		{
			return SUCCESS;
		}
	}
	else if ((strncmp(pStr1, "LED", 3) == 0) && (strncmp(pStr2, "LED", 3) == 0))
	{
		return SUCCESS;
	}
	return ERROR;
}

/**
  * @brief  判断一个LED是否正在闪烁
  *         
  * @param  name：LED名称 
  * @return 成功/失败
  */
static ErrorStatus Led_IsFlash(const char *name)
{
    for (int i=0; i<LED_FLASHING_MAX_QTY; i++)
    {
        if (ledFlashList[i].times == 0)
        {
            continue;
        }

        if (Led_Strcmp(ledFlashList[i].name, name) == SUCCESS)
        {
            return SUCCESS;
        }
    }
    return ERROR;
}

/**
  * @brief  添加闪烁LED
  *         
  * @param  name：LED名称   
  * @param  times：闪烁次数
  * @param  cycle：闪烁周期
  */
static void Led_AddFlashLed(const char *name, uint32_t times, uint32_t cycle)
{
	uint8_t i; 
	times = (times >= 0XFF) ? 0XFF : times;//0XFF表示永久闪烁
	/* 创建LED闪烁事件 */
	OSAL_EventRepeatCreate(COMP_LED, EVENT_LED_FLASH, LED_FLASH_EVT_PROC_CYCLE, EVT_PRIORITY_MEDIUM);

	/* 该LED已存在闪烁表里面，直接覆盖添加 */
	for (i=0; i<LED_FLASHING_MAX_QTY; i++)
	{
		if (Led_Strcmp(ledFlashList[i].name, name) == SUCCESS)
		{
			strcpy(ledFlashList[i].name, name);
			ledFlashList[i].count = 0;
			ledFlashList[i].times = times;
			ledFlashList[i].cycle = cycle;            
			return;
		}
	}

	/* 找LED闪烁表空闲的空间，添加一个新的闪烁LED */
	for (i=0; i<LED_FLASHING_MAX_QTY; i++)
	{
		if (ledFlashList[i].times == 0)
		{
			strcpy(ledFlashList[i].name, name);
			ledFlashList[i].count = 0;
			ledFlashList[i].times = times;
			ledFlashList[i].cycle = cycle;            
			return;
		}
	}
}

/**
  * @brief  删除闪烁的LED
  *         
  * @param  name：LED名称   
  */
static ErrorStatus Led_DelFlashLed(const char *name)
{
    ErrorStatus result = ERROR;
    FlagStatus ledFlashing = RESET;

    /* 删除一个闪烁LED */
    for (int i=0; i<LED_FLASHING_MAX_QTY; i++)
    {
        if (ledFlashList[i].times == 0)
        {
            continue;
        }

        if (Led_Strcmp(ledFlashList[i].name, name) == SUCCESS)
        {
            ledFlashList[i].times = 0;
            ledFlashList[i].count = 0;
            result = SUCCESS;
        }

        if (ledFlashList[i].times > 0)
        {
            ledFlashing = SET;
        }
    }

    /* LED闪烁表为空：删除LED闪烁事件 */
    if (ledFlashing != SET)
    {
        OSAL_EventDelete(COMP_LED, EVENT_LED_FLASH);
    }
    Led_SetEnterLed();
    return result;
}

/**
  * @brief  处理LED闪烁事件
  *         
  * @note   该事件100ms执行一次
  */
static void Led_ProcessFlashEvent(void)
{
	uint8_t i;
    uint32_t time = OSAL_GetTickCount();

	for (i=0; i<LED_FLASHING_MAX_QTY; i++)
	{
		if (ledFlashList[i].times == 0)
		{
            continue;
        }

        if (OSAL_PastTime(time, ledFlashList[i].timestamp) >= ledFlashList[i].cycle || ledFlashList[i].count == 0)
        {
            ledFlashList[i].timestamp = time;
            if ((++ledFlashList[i].count < ledFlashList[i].times) || (ledFlashList[i].times == 0xff))
            {
                if (Led_Strcmp(ledFlashList[i].name, "LED") == SUCCESS)
                {
                    (ledFlashList[i].count & 1) ? Led_Write(ledFlashList[i].name, 1) : Led_Write(ledFlashList[i].name, 0);
                }
                else
                {
                    (ledFlashList[i].count & 1) ? Led_Write(ledFlashList[i].name, 0) : Led_Write(ledFlashList[i].name, 1);
                }
            }
            else
            {
                if (Led_Strcmp(ledFlashList[i].name, "LED") == SUCCESS)
                {
                    Led_Write("LED", 0);
                }
                else
                {
                    Led_Write(ledFlashList[i].name, 1);
                }
                ledFlashList[i].times = 0;
                Led_SetEnterLed();
            }
        }
	}
    switch (ledAnimation)
    {
    case 3:
        Led_Write("LED789", 0);
        ledAnimation--;
        break;
    case 2:
        Led_Write("LED456", 0);
        ledAnimation--;
        break;
    case 1:
        Led_Write("LED123", 0);
        ledAnimation--;
        break;
    }
}

/**
  * @brief  处理LED控制事件
  * @note   
  * @param  name：LED名称
  * @param  ctrl：ON/OFF/FLASH
  * @param  times：闪烁次数（大于127表示永久闪烁）
  * @param  cycle：闪烁周期
  */
static ErrorStatus Led_SetApi(char *name, LedCtrlType_enum_t ctrl, uint8_t times, uint32_t cycle)
{
    ledAnimation = 0;
    LED_LOG("%s  %d, %d, %ld\r\n", name, ctrl, times, cycle);

    if (strcmp(name, "LED_PWM_R") == 0 ||
		strcmp(name, "LED_PWM_G") == 0 ||
		strcmp(name, "LED_PWM_B") == 0)
	{
		if(ctrl != LED_FLASH)
		{
			Device_ConfigCB(vTIMER_2, ENABLE);
			Device_SetPwm(vPWM_3, 2000, 0);
		}
		else
		{
			Device_ConfigCB(vTIMER_2, DISABLE);
			Device_SetPwm(vPWM_3, 2000, 100);
		}
	}
    if (strcmp(name, "LED_LOGO_W") == 0 ||
        strcmp(name, "LED_LOGO_R") == 0 ||
        strcmp(name, "LED_LOGO_G") == 0 ||
        strcmp(name, "LED_LOGO_B") == 0)
    {
        if (ctrl != LED_OFF)
        {
            Led_Write("LED_LOGO_W", 1);
            Led_Write("LED_LOGO_R", 1);
            Led_Write("LED_LOGO_G", 1);
            Led_Write("LED_LOGO_B", 1);
        }
    }
    
    if (ctrl == LED_ON)
    {
        if ((Led_Strcmp(name, "LED") == SUCCESS) && (Led_IsFlash("LED") == SUCCESS))
        {
            return ERROR;//键盘灯当前正在闪，不允许控制单独点亮
        }
        Led_Write(name, 0);
    }
    else if (ctrl == LED_OFF)
    {
        if (Led_DelFlashLed(name) == SUCCESS)
        {
            if (Led_Strcmp("LED", name) == SUCCESS && strlen(name) > 3)
            {
                Led_Write("LED", 0);
            }
        }
    #if defined(HC595_NONE)
        Led_Write("LED", 1);
    #else
        Led_Write(name, 1);
    #endif
    }
    else if (ctrl == LED_FLASH)
    {
        if (times == 0 && cycle == 0)
        {
            return Led_DelFlashLed(name);//0表示取消闪烁
        }

        Led_AddFlashLed(name, times * 2, cycle);
        Led_ProcessFlashEvent();
    }
    else if (ctrl == LED_ANIMATION)
    {
        OSAL_EventRepeatCreate(COMP_LED, EVENT_LED_FLASH, LED_FLASH_EVT_PROC_CYCLE, EVT_PRIORITY_MEDIUM);
        ledAnimation = 3;
    }
    return SUCCESS;
}

/**
  * @brief  LED任务函数
  *
  * @note   1.任务函数内不能写阻塞代码
  *         2.任务函数每次运行只处理一个事件
  *         
  * @param  event：当前任务的所有事件
  *
  * @return 返回未处理的事件
  */
static uint32_t Led_Task(uint32_t event)
{
	/* 系统启动事件 */
	if (event & EVENT_SYS_START)
	{
        static uint8_t flag = 0;
		LED_LOG("Led task start\r\n");

        OSAL_SetCompAlias(KOS_PARAM_LED_ALIAS); //配置LED组件的昵称
        // Led_Control(VHW_PIN_LED_BAT, 0);        // yxq   上电先点亮基本灯
        // Led_Control(VHW_PIN_LED_LOGO_B, 0);
        // Led_Control(VHW_PIN_LED_KEY, 0);//yxq  按键灯太亮先关掉

        if (flag == 0)
        {
            flag = 1;
            Device_RegisteredCB(vTIMER_2, Led_PwmSet);
        }
        Device_ConfigCB(vTIMER_2, ENABLE);
        Device_Enable(VHW_LED_PWM);
		return ( event ^ EVENT_SYS_START );
	}
    
    if (event & EVENT_SYS_MBOX)
    {
        LedSet_stu_t temp = {0};
        while (OSAL_MboxAccept(&temp))
        {
            Led_SetApi(temp.name, temp.ctrl, temp.times, temp.cycle);
        }
        return ( event ^ EVENT_SYS_MBOX );
    }

	/* 系统休眠事件 */
	if (event & EVENT_SYS_SLEEP)
	{
        Led_Control(VHW_PIN_LED_SHOW_LED,1);
		Led_Control(VHW_PIN_LED_KEY,1);
		Led_Control(VHW_PIN_LED_RED,1);
		Led_Control(VHW_PIN_LED_GREEN,1);
        Led_Control(VHW_PIN_LED_OPEN,1);
		Led_Control(VHW_PIN_LED_CLOSE,1);
		Led_Control(VHW_PIN_LED_BAT,1);
        Led_Control(VHW_PIN_LED_LP,1);
        Led_Control(VHW_PIN_LED_LOCKED,1);
        Led_Control(VHW_PIN_LED_FS,1);
        Led_Control(VHW_PIN_LED_BACK_R,1);
        Led_Control(VHW_PIN_LED_BACK_G,1);
        Led_Control(VHW_PIN_LED_CARD,1);
        Device_Write(VHW_PIN_LED_PWM_B, NULL, 0, 1);
        Device_Write(VHW_PIN_LED_PWM_R, NULL, 0, 1);
        Device_Write(VHW_PIN_LED_PWM_G, NULL, 0, 1);
        Device_Write(VHW_PIN_LED_LOGO_W, NULL, 0, 1);
        Device_Write(VHW_PIN_LED_LOGO_R, NULL, 0, 1);
        Device_Write(VHW_PIN_LED_LOGO_G, NULL, 0, 1);
        Device_Write(VHW_PIN_LED_LOGO_B, NULL, 0, 1);
        Led_Write("LED", 1);
        OSAL_EventDelete(COMP_LED, EVENT_LED_FLASH);
        memset(ledFlashList, 0, sizeof(ledFlashList));
        Device_ConfigCB(vTIMER_2, DISABLE);
        Device_Disable(VHW_LED_PWM);
		return ( event ^ EVENT_SYS_SLEEP );
    }
	
	/* LED闪烁事件 */
	if (event & EVENT_LED_FLASH)
	{
        Led_ProcessFlashEvent();
		return ( event ^ EVENT_LED_FLASH );
	}
	return 0;
}
COMPONENT_TASK_EXPORT(COMP_LED, Led_Task, 0);
